package xgenerator.ui.swing.model;

import java.util.List;
import java.util.Vector;

import javax.swing.JComboBox;
import javax.swing.table.DefaultTableModel;

import xgenerator.model.FieldMetadata;
import xgenerator.model.ModelMetadata;
import xgenerator.service.MetadataService;
import xgenerator.service.impl.MetadataServiceImpl;

/**
 * <p>
 * Title：MetadataTableModel
 * </p>
 * <p>
 * Description：
 * </p>
 * <p>
 * Copyright: Copyright (c) 2012
 * </p>
 * <p>
 * Company: liss
 * </p>
 * @author <a href="mailto:shushanlee@msn.com">liss</a>
 * @version 1.0
 * @see 
 * @since 1.0
 */
public class MetadataTableModel extends DefaultTableModel {

	/**
	 * Serializable
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * 列名列索引=0
	 */
	public static final int COLUMN_NAME_INDEX = 0;
	
	/**
	 * 属性名列索引=1
	 */
	public static final int PROPERTY_NAME_INDEX = 1;
	
	/**
	 * 显示名称列索引=2
	 */
	public static final int DISPLAY_NAME_INDEX = 2;
	
	/**
	 * 注释列索引=3
	 */
	public static final int COMMENTS_INDEX = 3;
	
	/**
	 * 数据类型列索引=4
	 */
	public static final int SQL_DATA_TYPE_INDEX = 4;
	
	/**
	 * 列长度列索引=5
	 */
	public static final int DATA_LENGTH_INDEX = 5;
	
	/**
	 * 精度列索引=6
	 */
	public static final int DATA_PRECISION_INDEX = 6;
	
	/**
	 * 刻度——小数点后位数，列索引=7
	 */
	public static final int DATA_SCALE_INDEX = 7;
	
	/**
	 * 属性类型列索引=8
	 */
	public static final int PROPERTY_TYPE_INDEX = 8;
	
	/**
	 * 可否为空列索引=9
	 */
	public static final int NULLABLE_INDEX = 9;
	
	/**
	 * 默认值列索引=10
	 */
	public static final int DATA_DEFAULT_INDEX = 10;
	
	/**
	 * 是否为键列索引=11
	 */
	public static final int IS_KEY_FIELD_INDEX = 11;
	
	/**
	 * 约束类型列索引=12
	 */
	public static final int CONSTRAINT_TYPE_INDEX = 12;
	
	/**
	 * 参照表列索引=13
	 */
	public static final int REFERENCING_TABLE_INDEX = 13;
	
	/**
	 * 参照列列索引=14
	 */
	public static final int REFERENCING_COLUMN_INDEX = 14;
	
	/**
	 * 删除规则索引=15
	 */
	public static final int DELETE_RULE_INDEX = 15;
	
	/**
	 * 是否作为查询字段=16
	 */
	public static final int IS_QUERY_FIELD_INDEX = 16;
	
	/**
	 * 查询模式=17
	 */
	public static final int QUERY_MODE_INDEX = 17;
	
	/**
	 * 组件类型=18
	 */
	public static final int COMPONENT_TYPE_INDEX = 18;
	
	/**
	 * 表列头
	 */
	public static final Object[] COLUMN_NAMES = {"列名", "属性名", "显示名", "注释", "SQL数据类型", "长度", "精度", "刻度", "属性类型", "可为空", "默认值", "键", "约束类型", "参照表", "参照列", "参照完整性约束", "可查询", "查询类型", "组件类型" };

	/**
	 * 列数据类型
	 */
	public static final Class[] COLUMN_CLASS = { String.class, // 列名
			String.class, // 属性名
			String.class, // 中文名称
			String.class, // 注释
			JComboBox.class, // 数据类型
			Integer.class, // 长度
			Integer.class, // 精度
			Integer.class, // 刻度
			JComboBox.class, // 属性类型
			Boolean.class, // 可为空
			String.class, // 默认值/表达式
			Boolean.class, // 键
			JComboBox.class, // 约束类型
			JComboBox.class, // 参照表
			JComboBox.class, // 参照列
			JComboBox.class, // 参照完整性约束
			Boolean.class, // 查询设置
			JComboBox.class, // 查询类型
			JComboBox.class // 组件类型
	};
	
	/**
	 * service
	 */
	private MetadataService metadataService;

	/**
	 * 单元格可否编辑矩阵
	 */
	private Vector<Vector<Boolean>> cellEditableVector;

	/**
	 * 新建数据模型，并初始化数据
	 * @param datasourceName
	 * @param tableName
	 */
	public MetadataTableModel(String datasourceName, String tableName) {
		this.metadataService = new MetadataServiceImpl();
		this.updateDataVector(datasourceName, tableName);
	}
	
	/**
	 * 新建数据模型，并用空行初始化
	 */
	public MetadataTableModel() {
		this(null, null);
	}
	
	/**
	 * <p>
	 * Title：cellEditableVector getter
	 * </p>
	 * @author <a href="mailto:shushanlee@msn.com">liss</a>
	 * @return
	 */
	public Vector<Vector<Boolean>> getCellEditableVector() {
		return this.cellEditableVector;
	}

	/**
	 * <p>
	 * Title：cellEditableVector setter
	 * </p>
	 * @author <a href="mailto:shushanlee@msn.com">liss</a>
	 * @param cellEditableVector
	 */
	public void setCellEditableVector(Vector<Vector<Boolean>> cellEditableVector) {
		this.cellEditableVector = cellEditableVector;
	}
	
	/**
	 * <p>
	 * Title：设置指定单元格可否编辑
	 * </p>
	 * @author <a href="mailto:shushanlee@msn.com">liss</a>
	 * @param editable
	 * @param row
	 * @param column
	 */
	public void setCellEditableAt(boolean editable, int row, int column) {
//		this.editableVector.get(row).setElementAt(editable, column);
		Vector rowVector = (Vector)this.cellEditableVector.elementAt(row);
		rowVector.setElementAt(editable, column);
        fireTableCellUpdated(row, column);
	}
	
	/**
	 * <p>
	 * Title：构造一行的所有单元格可否编辑Vector
	 * </p>
	 * @author <a href="mailto:shushanlee@msn.com">liss</a>
	 * @return
	 */
	private Vector<Boolean> mapRowEditableVector(FieldMetadata fieldMetadata) {
		int columnCount = COLUMN_NAMES.length;
		
		Vector<Boolean> oneRowCellEditable = new Vector<Boolean>(columnCount);
		
		for(int j=0; j<columnCount; j++) {
			if(j == CONSTRAINT_TYPE_INDEX) {
				if(fieldMetadata.isKeyField()) {
					oneRowCellEditable.add(new Boolean(true));
				} else {
					oneRowCellEditable.add(new Boolean(false));
				}
			} else if(j == REFERENCING_TABLE_INDEX || j == REFERENCING_COLUMN_INDEX || j == DELETE_RULE_INDEX) {
				if(fieldMetadata.isKeyField() && ConstraintTypeComboBoxModel.FK_TYPE.equals(fieldMetadata.getConstraintType())) {
					oneRowCellEditable.add(new Boolean(true));
				} else {
					oneRowCellEditable.add(new Boolean(false));
				}
			} else if(j == QUERY_MODE_INDEX) {
				if(fieldMetadata.isQueryField()) {
					oneRowCellEditable.add(new Boolean(true));
				} else {
					oneRowCellEditable.add(new Boolean(false));
				}
			} else {
				oneRowCellEditable.add(new Boolean(true));
			}
		}
		
		return oneRowCellEditable;
	}
	
	/**
	 * <p>
	 * Title：构造表格单元格可否编辑矩阵
	 * </p>
	 * @author <a href="mailto:shushanlee@msn.com">liss</a>
	 * @param rowCount
	 */
	private Vector<Vector<Boolean>> mapCellEditableVector(List<FieldMetadata> fieldMetadatas) {
		int rowCount = fieldMetadatas.size();
		
		Vector<Vector<Boolean>> tableCellEditableMatrix = new Vector<Vector<Boolean>>(rowCount);
		
		for(int i=0; i<rowCount; i++) {
			tableCellEditableMatrix.add(mapRowEditableVector(fieldMetadatas.get(i)));
		}
		return tableCellEditableMatrix;
	}
	
	/**
	 * <p>
	 * Title：添加TableModel行时，同时添加单元格可否编辑的矩阵的一行
	 * </p>
	 * @author <a href="mailto:shushanlee@msn.com">liss</a>
	 * @param rowIndex
	 */
	private void insertRowEditable(int rowIndex) {
		FieldMetadata fieldMetadata = buildNewRowData();
		this.cellEditableVector.insertElementAt(mapRowEditableVector(fieldMetadata), rowIndex);
	}
	
	/**
	 * <p>
	 * Title：删除TableModel行时，同时删除单元格可否编辑的矩阵的一行
	 * </p>
	 * @author <a href="mailto:shushanlee@msn.com">liss</a>
	 * @param rowIndex
	 */
	private void removeRowEditable(int rowIndex) {
		this.cellEditableVector.remove(rowIndex);
	}
	
	/**
	 * <p>
	 * Title：构造一个数据TableColumnMetadataBean
	 * </p>
	 * @author <a href="mailto:shushanlee@msn.com">liss</a>
	 * @return
	 */
	private FieldMetadata buildNewRowData() {
		FieldMetadata fieldMetadata = new FieldMetadata();
		
		fieldMetadata.setNullable(true);
		fieldMetadata.setKeyField(false);
		
		return fieldMetadata;
	}
	
	/**
	 * <p>
	 * Title：插入新行
	 * </p>
	 * @author <a href="mailto:shushanlee@msn.com">liss</a>
	 * @param rowIndex
	 */
	public void insertNewRow(int rowIndex) {
		Object[] rowData = this.mapRowData(this.buildNewRowData());
		this.insertRow(rowIndex, rowData);
		this.insertRowEditable(rowIndex);
	}
	
	/**
	 * <p>
	 * Title：重写删除行方法，删除一行，并删除对应的行单元格可否编辑状态
	 * </p>
	 * @param row
	 * @see javax.swing.table.DefaultTableModel#removeRow(int)
	 */
	@Override
	public void removeRow(int row) {
		super.removeRow(row);
		this.removeRowEditable(row);
	}
	
	/**
	 * <p>
	 * Title：将TableColumnMetadataBean映射为一个数据表格行
	 * </p>
	 * @author <a href="mailto:shushanlee@msn.com">liss</a>
	 * @param oneFieldMetadata
	 * @return
	 */
	private Object[] mapRowData(FieldMetadata oneFieldMetadata) {
		int columnCount = MetadataTableModel.COLUMN_NAMES.length;
		Object[] oneRowData = new Object[columnCount];

		oneRowData[COLUMN_NAME_INDEX] = oneFieldMetadata.getColumnName();
		oneRowData[PROPERTY_NAME_INDEX] = oneFieldMetadata.getPropertyName();
		oneRowData[DISPLAY_NAME_INDEX] = oneFieldMetadata.getDisplayName();
		oneRowData[COMMENTS_INDEX] = oneFieldMetadata.getComments();
		oneRowData[SQL_DATA_TYPE_INDEX] = oneFieldMetadata.getSqlDataType();
		oneRowData[DATA_LENGTH_INDEX] = oneFieldMetadata.getDataLength();
		oneRowData[DATA_PRECISION_INDEX] = oneFieldMetadata.getDataPrecision();
		oneRowData[DATA_SCALE_INDEX] = oneFieldMetadata.getDataScale();
		oneRowData[PROPERTY_TYPE_INDEX] = oneFieldMetadata.getPropertyType();
		oneRowData[NULLABLE_INDEX] = oneFieldMetadata.isNullable();
		oneRowData[DATA_DEFAULT_INDEX] = oneFieldMetadata.getDataDefault();
		oneRowData[IS_KEY_FIELD_INDEX] = oneFieldMetadata.isKeyField();
		oneRowData[CONSTRAINT_TYPE_INDEX] = oneFieldMetadata.getConstraintType();
		oneRowData[REFERENCING_TABLE_INDEX] = oneFieldMetadata.getReferencingTable();
		oneRowData[REFERENCING_COLUMN_INDEX] = oneFieldMetadata.getReferencingColumn();
		oneRowData[DELETE_RULE_INDEX] = oneFieldMetadata.getDeleteRule();
		
		return oneRowData;
	}
	
	/**
	 * <p>
	 * Title：构造TableModel的DataVector
	 * </p>
	 * @author <a href="mailto:shushanlee@msn.com">liss</a>
	 * @param fieldMetadatas
	 * @return
	 */
	private Object[][] mapDataVector(List<FieldMetadata> fieldMetadatas) {
		int rowCount = fieldMetadatas.size();
		int columnCount = COLUMN_NAMES.length;
		
		Object[][] rowDataArray = new Object[rowCount][columnCount];
		for (int i = 0; i < rowDataArray.length; i++) {
			rowDataArray[i] = mapRowData(fieldMetadatas.get(i));
		}
		
		return rowDataArray;
	}

	/**
	 * <p>
	 * Title：更新TableModel的DataVector数据
	 * </p>
	 * @author <a href="mailto:shushanlee@msn.com">liss</a>
	 * @param datasourceName
	 * @param tableName
	 */
	public ModelMetadata updateDataVector(String datasourceName, String tableName) {
		ModelMetadata modelMetadata = this.metadataService.getModelMetadata(datasourceName, tableName);
		List<FieldMetadata> fieldMetadatas = modelMetadata.getFieldMetadatas();
		
		/*
		 * editableVector的初始化一定要在setDataVector之前
		 */
		this.setCellEditableVector(mapCellEditableVector(fieldMetadatas));
		this.setDataVector(mapDataVector(fieldMetadatas), COLUMN_NAMES);
		
		return modelMetadata;
	}
	
	/**
	 * <p>
	 * Title：使表格能识别不同的数据类型
	 * </p>
	 * @author <a href="mailto:shushanlee@msn.com">liss</a>
	 * @param columnIndex
	 * @return
	 * @see javax.swing.table.AbstractTableModel#getColumnClass(int)
	 */
	@Override
	public Class getColumnClass(int columnIndex) {
//		Object cellObj = getValueAt(0, columnIndex);
//		if(null != cellObj) {
//			return cellObj.getClass();
//		} else {
//			return super.getColumnClass(columnIndex);
//		}
		
		return COLUMN_CLASS[columnIndex];
	}
	
	/**
	 * <p>
	 * Title：
	 * </p>
	 * @author <a href="mailto:shushanlee@msn.com">liss</a>
	 * @param row
	 * @param column
	 * @return
	 * @see javax.swing.table.DefaultTableModel#isCellEditable(int, int)
	 */
	@Override
	public boolean isCellEditable(int row, int column) {
//		return super.isCellEditable(row, column);
//		return this.editableVector.get(row).get(column);
		Vector<Boolean> rowVector = (Vector<Boolean>) this.cellEditableVector.elementAt(row);
		return rowVector.elementAt(column);
	}

}
